#include "atom.h"
#include "drv_uart.h"
#include <stdio.h>
#include <pthread.h>
#include <termios.h>
#include <stdlib.h>
#include "mraa/uart.h"
#include "syslog.h"

#define UART_RX_SIZE (8192)
#define UART_TX_SIZE (8192)

#define UART_READ_BUFSIZE (1024)

static uint8_t _rx_buffer[UART_RX_SIZE] = { 0 };
static uint8_t _tx_buffer[UART_TX_SIZE] = { 0 };


#define SAVEKEY(key) \
    {char ch = key; \
    int level = get_cc(); \
    ringPut(&up->Protected.ops->rxRing, (char*)&ch, 1); \
    set_cc(level); }\

static void *thread_for_uart(void* param)
{
    UpboardUart* uart = (UpboardUart*)param;
    char buf[UART_READ_BUFSIZE] = { 0 };

    for (;;) {
        if (mraa_uart_data_available(uart->Protected.context, 50)) {
            int count = mraa_uart_read(uart->Protected.context, buf, UART_READ_BUFSIZE);
            if (count > 0) {
                ringPut(&uart->super.Protected.ops->rxRing, buf, count);
            }
        }
    }
    return NULL;
}

int uart_ioctl(SioBase* sio, int function, void* arg)
{
    return NG;
}

void uart_blocking_send(SioBase* sio, const char* buffer, size_t size)
{
    UpboardUart* uart = (UpboardUart*)sio;

    mraa_uart_write(uart->Protected.context, buffer, size);
}


void UpUartCreate(UpboardUart* sio, const char *name, SIO_PARAM* param)
{
    pthread_t thread;

    sio->Protected.owner = 0;

    sio->Protected.ops.Ioctl = uart_ioctl;
    sio->Protected.ops.BufferedSend = NULL;
    sio->Protected.ops.BlockingSend = uart_blocking_send;

    SioCreate(&sio->super, name, param, &sio->Protected.ops, _rx_buffer, UART_RX_SIZE, _tx_buffer, UART_TX_SIZE);
    mraa_uart_context context = mraa_uart_init_raw("/dev/ttyS4");
    if (context != NULL) {
        sio->Protected.context = (POINTER)context;

        mraa_uart_set_baudrate(context, param->baud);
        mraa_uart_set_mode(context, param->dataBits, (mraa_uart_parity_t)param->parity, (int)param->stopBit);
        mraa_uart_set_flowcontrol(context, (mraa_boolean_t)param->xonxoff, (mraa_boolean_t)param->ctsrts);

        pthread_create(&thread, NULL, thread_for_uart, (void*)sio);
    }
    else {
        SYSLOG(LOG_ERR, "open uart failure!");
    }
}
